package cn.enilu.guns.admin.modular.thread;

import cn.enilu.guns.admin.equipment.service.EntranceGuardService;
import cn.enilu.guns.admin.equipment.transform.GetDeviceDataTransform;
import cn.enilu.guns.bean.dto.RealTimeRecordDto;
import cn.enilu.guns.bean.entity.door.EquipmentInfo;
import cn.enilu.guns.bean.entity.door.EventType;
import cn.enilu.guns.service.system.impl.ConstantFactory;
import cn.enilu.guns.utils.Lists;
import cn.enilu.guns.utils.Maps;
import cn.enilu.guns.utils.RandomUtils;
import cn.enilu.guns.utils.SpringContextUtil;
import com.google.common.collect.Sets;

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReadTimeThread extends Thread {
    private static Lock lock = new ReentrantLock();
    private static EntranceGuardService entranceGuardService = SpringContextUtil.getBean("entranceGuardService");
    public static long startTime = System.currentTimeMillis();
    /**
     * 每个人返回的监控数据
     */
    private static Map<String, Queue<RealTimeRecordDto>> realTimeRecordDtoMap = Maps.newHashMap();
    /**
     * 所有人需要监控的设备数据
     * String：每个请求的KEY，用户ID+IP
     * Long: 设备ID
     * EquipmentInfo： 设备对象
     */
    private static Map<String, Map<Long, EquipmentInfo>> everyUserEquipmentInfoMap = Maps.newHashMap();
    /**
     * 每个设备有在监控在监控的人数，监控设备组
     * String：每个请求的KEY，用户ID+IP
     * Long: 设备ID
     * EquipmentInfo： 设备对象
     */
    private static Map<Long, ReadTimeUser> readTimeUserMap = Maps.newHashMap();

    //静态内部类
    private static class ReadTimeSingletonHandler {
        private final static ReadTimeThread instance = new ReadTimeThread();
    }

    public static ReadTimeThread getInstance() {
        return ReadTimeSingletonHandler.instance;
    }

    private ReadTimeThread(){

    }

    public static void startRead(){
        ReadTimeThread readTimeThread = new ReadTimeThread();
        readTimeThread.start();
    }

    @Override
    public void run() {
        try {
            if(!lock.tryLock()){
                return;
            }
            while (true) {
                //测试模拟数据代码
//                Thread.sleep(1000L);
                long endTime = System.currentTimeMillis();
                if (endTime - startTime > 30 * 1000) {
                    System.out.println("超过30秒没有人拉取实时数据，停止读取设备数据线程");
                    return;
                }
                if (readTimeUserMap.size() != 0) {
                    //获取真实数据
                    getRtLog();
                    //测试模拟数据
//                    for (Map.Entry<Long, ReadTimeUser> readTimeUser : readTimeUserMap.entrySet()) {
//                        //循环获取设备实时数据，装入结果集
//                        RealTimeRecordDto realTimeRecordDto = new RealTimeRecordDto();
//                        realTimeRecordDto.setAreaName(RandomUtils.getNumberRandom(2));
//                        realTimeRecordDto.setEventType(RandomUtils.getNumberRandom(1));
//                        Iterator<String> iterator = readTimeUser.getValue().getUserKeySet().iterator();
//                        while (iterator.hasNext()) {
//                            Queue<RealTimeRecordDto> realTimeRecordDtos = realTimeRecordDtoMap.get(iterator.next());
//                            if(null != realTimeRecordDtos) {
//                                realTimeRecordDtos.add(realTimeRecordDto);
//                            }
//                        }
//                    }
                } else {
                    System.out.println("没有人在获取实时数据，停止读取设备数据线程");
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private void getRtLog(){
        for (Map.Entry<Long, ReadTimeUser> readTimeUser : readTimeUserMap.entrySet()) {
//            int hCommPro = entranceGuardService.getHCommPro(readTimeUser.getValue().getEquipmentInfo().getIpAddress());
//
//            String rtLog = entranceGuardService.getRTLog(hCommPro);
            String rtLog = entranceGuardService.getRTLog(readTimeUser.getValue().gethCommPro());
            if ("0".equals(rtLog)) {
                continue;
            }
            EquipmentInfo equipmentInfo = readTimeUser.getValue().getEquipmentInfo();
            RealTimeRecordDto realTimeRecordDto = GetDeviceDataTransform.transformToRealTimeRecord(rtLog);
            realTimeRecordDto.setEquipmentId(equipmentInfo.getId());
            realTimeRecordDto.setEquipmentName(equipmentInfo.getEquipmentName());
            realTimeRecordDto.setAreaName(ConstantFactory.me().getAreaName(equipmentInfo.getAreaId().intValue()));
            realTimeRecordDto.setVerifiedName(ConstantFactory.me().getVerifiedName(realTimeRecordDto.getVerified()));

            realTimeRecordDto.setDoorName(realTimeRecordDto.getEquipmentName() + "-" + realTimeRecordDto.getDoorId());
            realTimeRecordDto.setUserName(ConstantFactory.me().getUserNameById(realTimeRecordDto.getPin()));
            realTimeRecordDto.setInoutState(ConstantFactory.me().getInoutStateName(Integer.valueOf(realTimeRecordDto.getInoutState())));
            Iterator<String> iterator = readTimeUser.getValue().getUserKeySet().iterator();
            while (iterator.hasNext()) {
                Queue<RealTimeRecordDto> realTimeRecordDtos = realTimeRecordDtoMap.get(iterator.next());
                if(null != realTimeRecordDtos) {
                    realTimeRecordDtos.add(realTimeRecordDto);
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ReadTimeThread readTimeThread1 = ReadTimeThread.getInstance();
        readTimeThread1.start();
        ReadTimeThread readTimeThread2 = ReadTimeThread.getInstance();
        if (!readTimeThread2.isAlive()) {
            System.out.println("启动readTimeThread2");
        } else {
            System.out.println("readTimeThread1正在启动");
        }

        realTimeRecordDtoMap.put("1", null);
        Thread.sleep(3000L);
        realTimeRecordDtoMap.clear();
    }

    public static void resetStartTime() {
        startTime = System.currentTimeMillis();
    }

    private static Random random = new Random();
    /**
     * 連接設備
     */
    private static boolean connectHCommPro(ReadTimeUser readTimeUser){
        //正式链接设备代码
        int hCommPro = entranceGuardService.getHCommPro(readTimeUser.getEquipmentInfo().getIpAddress());
        if(hCommPro > 0){
            readTimeUser.sethCommPro(hCommPro);
            return true;
        }
        //测试链接设备代码
//        int hCommPro = random.nextInt(100);
//        if(hCommPro > 10){
//            readTimeUser.sethCommPro(hCommPro);
//            return true;
//        }
        return false;
    }
    /**
     * 添加用户需要监控的设备
     * 1.添加人员请求的设备,--如果新添加，则初始化该人员实时数据的结果集
     * 2.添加到这个设备的监控人员Set中
     * 3.更新需要监控的设备Map
     * @param key           键
     * @param equipmentInfo 设备
     */
    public static boolean putEquipmentInfo(String key, EquipmentInfo equipmentInfo) {

        //添加到这个设备的监控人员Set中
        ReadTimeUser readTimeUser = readTimeUserMap.get(equipmentInfo.getId());
        if(null != readTimeUser){
            readTimeUser.putUserKey(key);
        }else{
            readTimeUser = new ReadTimeUser();
            readTimeUser.putUserKey(key);
            readTimeUser.setEquipmentInfo(equipmentInfo);
            //連接設備
            if(!connectHCommPro(readTimeUser)){
                //设备连接不成功
                return false;
            }else{
                //设备连接成功，则加入监控设备组
                readTimeUserMap.put(equipmentInfo.getId(),readTimeUser);
            }
        }
        //添加人员请求的设备
        Map<Long, EquipmentInfo> equipmentInfoMap = everyUserEquipmentInfoMap.get(key);
        if (null != equipmentInfoMap) {
            equipmentInfoMap.put(equipmentInfo.getId(),equipmentInfo);
        }else{
            equipmentInfoMap = Maps.newHashMap();
            equipmentInfoMap.put(equipmentInfo.getId(),equipmentInfo);
            //加入用户的监控设备组
            everyUserEquipmentInfoMap.put(key,equipmentInfoMap);
            //如果新添加，则初始化该人员实时数据的结果集
            Queue<RealTimeRecordDto> realTimeRecordDtos = new ConcurrentLinkedQueue<>();
            realTimeRecordDtoMap.put(key,realTimeRecordDtos);
        }

        return true;
    }

    /**
     * 删除用户需要监控的设备
     * 1.添加人员请求的设备,--如果新添加，则初始化该人员实时数据的结果集
     * 2.添加到这个设备的监控人员Set中
     * 3.更新需要监控的设备Map
     * @param key           键
     * @param equipmentInfo 设备
     */
    public static void removeEquipmentInfo(String key, EquipmentInfo equipmentInfo) {
        //删除人员请求的设备
        Map<Long, EquipmentInfo> equipmentInfoMap = everyUserEquipmentInfoMap.get(key);
        if (null != equipmentInfoMap) {
            equipmentInfoMap.remove(equipmentInfo.getId());
            if(equipmentInfoMap.size() == 0){
                //如果当前没有监控的设备，删除该人员实时数据的结果集
                realTimeRecordDtoMap.remove(key);
                //删除监控的设备Map
                everyUserEquipmentInfoMap.remove(key);
            }
        }

        //从到这个设备的监控人员Set中删除该人员
        removeUserKeyFromReadTimeUserMap(equipmentInfo.getId(),key);
    }

    /**
     * 清空用户的监控的设备
     * 1.从用户设备Map中清除该用户的监控设备数据
     * 2.从到这个设备的监控人员Set中，删除该人员
     * 3.删除该人员实时数据的结果集
     * 4.更新需要监控的设备Map
     * @param key
     */
    public static void clearEquipmentInfoMap(String key) {
        //从用户设备Map中清除该用户的监控设备数据
        Map<Long, EquipmentInfo> equipmentInfoMap = everyUserEquipmentInfoMap.get(key);
        if (null != equipmentInfoMap) {
            everyUserEquipmentInfoMap.remove(key);
            //从到这个设备的监控人员Set中，删除该人员
            for (Map.Entry<Long,EquipmentInfo> entry : equipmentInfoMap.entrySet()) {
                removeUserKeyFromReadTimeUserMap(entry.getKey(),key);
            }
        }
        //删除该人员实时数据的结果集
        realTimeRecordDtoMap.remove(key);
    }

    private static void removeUserKeyFromReadTimeUserMap(Long equipmentInfoId,String userKey){
        ReadTimeUser readTimeUser = readTimeUserMap.get(equipmentInfoId);
        if(readTimeUser != null){
            readTimeUser.removeUserKey(userKey);
            if(readTimeUser.getUserKeySet().size() == 0 ){
                readTimeUserMap.remove(equipmentInfoId);
            }
        }
    }

    /**
     * 获取用户的实时监控结果集
     * @param userKey
     * @return
     */
    public static Queue<RealTimeRecordDto> getRealTimeRecordDto(String userKey){
        return realTimeRecordDtoMap.get(userKey);
    }

    public static Map<Long, EquipmentInfo> getUserEquipmentInfoMap(String userKey){
         return everyUserEquipmentInfoMap.get(userKey);
    }

}
